// package pcapraw
package pcapraw

import (
	"net"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/pcap"
	"github.com/pkg/errors"
)

type PcapRaw interface {
	// ReadGoPkt 读取一个 gopacket.Packet
	ReadGoPkt(timeout time.Duration) (gopacket.Packet, error)

	// WriteLayers 向网络接口注入一个报文
	WriteLayers(layers []gopacket.SerializableLayer) error

	// WriteRaw 向网络接口注入一个 raw 报文
	WriteRaw(data []byte) error

	// Close 关闭句柄
	Close()
}

// findPcapInterfaceByIP 根据接口IP地址查找接口的 `\Device\NPF_{GUID}` 名称
// windows 系统的 pcap网络接口名称的正确格式为 `\Device\NPF_{GUID}`，可以通过命令行 `getmac` 工具获取
func findPcapInterfaceByIP(localIP net.IP) (string, error) {
	pcapIfs, err := pcap.FindAllDevs()
	if err != nil {
		return "", err
	}

	for _, pIf := range pcapIfs {
		for _, addr := range pIf.Addresses {
			if addr.IP.Equal(localIP) {
				return pIf.Name, nil
			}
		}
	}

	return "", errors.New("no such network interface")
}

// serializeLayers 系列化 []gopacket.SerializableLayer
func serializeLayers(layers []gopacket.SerializableLayer) ([]byte, error) {
	var (
		buffer = gopacket.NewSerializeBuffer()
		opt    = gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
	)

	layersLen := len(layers)
	for i := layersLen - 1; i >= 0; i-- {
		if err := layers[i].SerializeTo(buffer, opt); err != nil {
			return nil, err
		}
		buffer.PushLayer(layers[i].LayerType())
	}

	return buffer.Bytes(), nil
}
